<template>
  <div> 
    <!-- 背景 -->
    <div class="bg"></div>
    <div class="container">
      <h3>第{{ level }}关</h3>
      <div class="wraper">
        <div class="scene-container">
          <div class="scene-inner">
            <!-- :style="{transform:`translateX(${item.x}%) translateY(${item.y}%)`}" -->
            <!-- 默认值 status=0 ,选中到队列中status =1 ,三连匹配成功 status = 2 -->
            <div
              v-for="(item, index) in scene"
              :key="item.id"
              class="symbol"
              :style="{
                transform: `translateX(${
                  item.status === 0 ? item.x : item.status === 1 ? sortedQueue[item.id] : -1000
                }%)
                   translateY(${item.status === 0 ? item.y : 885}%)`,
                opacity: item.status < 2 ? 1 : 0,
              }"
              @click="clickSymbol(index)"
            >
              <div
                class="symbol-inner"
                :style="{ backgroundColor: item.isCover ? '#999' : '#fff' }"
              >
                <img :src="'/' + item.icon" alt="" style="100%" />
              </div>
            </div>
          </div>
        </div>
        <div class="queue-container"></div>
        <div class="btn-container">
          <button @click="tanchu">弹出</button>
          <button @click="chexiao">撤销</button>
          <button @click="wash">洗牌</button>
          <button @click="leveNext">下一关</button>
        </div>
      </div>
      <!-- 蒙版 -->
      <div class="modal" v-if="finished">
        <h1>{{ tipText }}</h1>
        <button @click="restart">重新开始</button>
      </div>
    </div>
    <!-- 背景音乐 -->
    <div><audio src="/bgmusic.mp3"   autoplay ></audio></div>
  </div> 
</template>

<script setup>
// import { fa } from "element-plus/es/locale";
// import { finished } from "stream";
import { ref,watchEffect } from "vue";
const maxLevel = 50; // 关卡总数
const icons = [
  "1.png",
  "2.gif",
  "3.gif",
  "4.gif",
  "5.gif",
  "6.gif",
  "7.gif",
  "8.gif",
  "9.gif",
  "10.gif",
  "11.gif",
  "12.gif",
  "13.gif",
  "14.gif",
  "15.gif",
  "16.gif",
  "17.gif",
];
let level = ref(1);
const queue = ref([]); //下方选中的元数据
const finished = ref(false); //是否游戏完成
const tipText = ref(""); //提示
const sortedQueue = ref([]); //排序后拿到的每个元对象对应的x坐标
const flag = ref(false); //

// 1. 生成随机id
const randomString = (len) => {
  const pool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  let res = "";
  // Math.random() -->(0,1)随机小数
  while (len >= 0) {
    res += pool[Math.floor(pool.length * Math.random())]; //pool.length; pool[n]
    len--;
  }
  return res;
};

// 2. 生成关卡元对象数据
const makeScene = (level) => {
  // 随机位置
  const curLevel = Math.min(maxLevel, level); // 1.当前关卡
  const iconPool = icons.slice(0, 2 * curLevel); //2. 对应的图标数组
  const scene = []; //3. 元数据对象
  // 4. 根据关卡，得行列数范围(正方形), 设置地图
  const range = [
    [2, 6],
    [1, 6],
    [1, 7],
    [0, 7],
    [0, 8],
  ][Math.min(4, curLevel - 1)];

  // 7. 偏移量
  const offsetPool = [0, 25, -25, 50, -50].slice(0, curLevel + 1);
  // 5. 生成一个随机位置
  const randomSet = (icon) => {
    const offset = offsetPool[Math.floor(offsetPool.length * Math.random())];
    const row = range[0] + Math.floor((range[1] - range[0]) * Math.random()); //[2,6]地图-->例如 (2~4+2)的范围
    const column = range[0] + Math.floor((range[1] - range[0]) * Math.random()); // 例如(2~4+2)的范围
    scene.push({
      isCover: false,
      status: 0,
      icon: icon,
      id: randomString(4),
      x: column * 100 + offset,
      y: row * 100 + offset,
    });
  };
  // 8. 如果级别高就添加重复icon，元对象多些, 关卡5以上...
  let compareLevel = curLevel;
  while (compareLevel > 0) {
    iconPool.push(...iconPool.slice(0, Math.min(10, 2 * (compareLevel - 5))));
    compareLevel -= 5;
  }
  console.log(iconPool);

  //6.生成多个元对象数据
  for (let j = 0; j < iconPool.length; j++) {
    //  iconPool变
    for (let i = 0; i < 6; i++) {
      randomSet(iconPool[j]);
    }
  }
  return scene;
};

//3. 检查是否被覆盖（检查碰撞）
const checkCover = (scene) => {
  const updateScene = scene;
  // 1. 双循环遍历：每个元数据与其他数据是否碰撞
  for (let i = 0; i < updateScene.length; i++) {
    const cur = updateScene[i]; // 2. 当前一个元数据
    cur.isCover = false; //3.先假定都不是覆盖的
    if (cur.status != 0) continue; // 4. 如果status 不是0,说明已经选中了不再判断了
    const { x: x1, y: y1 } = cur; // 5 拿到坐标
    // 6. 拿对角线坐标
    const x2 = x1 + 100;
    const y2 = y1 + 100;
    for (let j = i + 1; j < updateScene.length; j++) {
      const compare = updateScene[j];
      if (compare.status != 0) continue;
      const { x: xc1, y: yc1 } = compare;
      const xc2 = xc1 + 100;
      const yc2 = yc1 + 100;
      // 7. 判断碰撞 :没交集范围取反
      if (!(x1 >= xc2 || x2 <= xc1 || y1 >= yc2 || y2 <= yc1)) {
        cur.isCover = true;
        break;
      }
    }
  }
  //scene.value = updateScene;//全局
};

const scene = ref(makeScene(level.value));
// 4.洗牌算法
const washScene = (level, scene) => {
  // 修改已经生产的元数据
  // 随机位置
  const updateScene = scene.sort(() => Math.random() - 0.5); // sort() 方法来洗牌
  console.log("+++++++++++++++++++++++++++");
  console.log(updateScene);
  console.log("+++++++++++++++++++++++++++");
  // 4. 根据关卡，得行列数范围(正方形), 设置地图
  const range = [
    [2, 6],
    [1, 6],
    [1, 7],
    [0, 7],
    [0, 8],
  ][Math.min(4, level - 1)];

  // 7. 偏移量
  const offsetPool = [0, 25, -25, 50, -50].slice(0, level + 1);
  // 5. 修改一个随机位置
  const randomSet = (symbol) => {
    // symbol 一个元数据
    const offset = offsetPool[Math.floor(offsetPool.length * Math.random())];
    const row = range[0] + Math.floor((range[1] - range[0]) * Math.random()); //[2,6]地图-->例如 (2~4+2)的范围
    const column = range[0] + Math.floor((range[1] - range[0]) * Math.random()); // 例如(2~4+2)的范围
    // 在原来的数据上修改(注意不push添加)
    symbol.x = column * 100 + offset;
    symbol.y = row * 100 + offset;
    symbol.isCover = false;
  };
  //6.循环每个元对象数据，来修改每个元对象的数据
  for (let i = 0; i < updateScene.length; i++) {
    // updateScene 注意不是图标数组了，是已经生成的元数据上修改
    if (updateScene[i].status != 0) continue;
    randomSet(updateScene[i]);
  }
  return scene;
};

// 4 洗牌
const wash = () => {
  checkCover(washScene(level.value, scene.value));
};

//5.点击元对象
const clickSymbol = (id) => {
  //是否点击
  if(flag.value || finished.value) return;
  //1.拿到一份元素数据
  const symbol = scene.value[id];
  // console.log(symbol);
  //2.判断不处理情况
  if (symbol.isCover || symbol.status != 0) return;
  //3.设置选中
  symbol.status = 1;
  //4.push 到队列中
  queue.value.push(symbol);
  //设置防止其他点击
  flag.value = true;
  // 500延时
  setTimeout(() => { // console.log(queue.value);
  //5.拿所有与当前元数据的icon相同的队列里的数据
  const filterSame = queue.value.filter((item) => item.icon === symbol.icon);
  // console.log(filterSame);
  //6.判断是否是三连匹配 如果是：给scene中对应的 symbol.status = 2;
  if (filterSame.length == 3) {
    //8.留下队列中不一样的剩余内容重新赋值
    queue.value = queue.value.filter((item) => item.icon !== symbol.icon);
    //7.给scene中对应的 symbol.status = 2;
    for (const queueOne of filterSame) {
      const findSymbol = scene.value.find(
        (symbol) => symbol.id === queueOne.id
      );
      if (findSymbol) findSymbol.status = 2; //三连配成功了
    }
  }
  // 9.条件如果当前关卡完成到下一关: 否则每次点击都判断碰撞
  if (!scene.value.find((item) => item.status !== 2)) {
    //14.判断是否都通关了
    if(level.value == maxLevel){
      tipText.text = "完成挑战";
      finished.value = true;
      return
    }
    //10.下一关
    //alert("恭喜过关！！")
    level.value = level.value + 1;
    //11.队列清空
    queue.value = [];
    //12.重新初始化和判断碰撞
    scene.value = makeScene(level.value);
    checkCover(scene.value);
    //checkCover(makeScene(level.value))
  } else {
    checkCover(scene.value);
  }
  //每次点击都判断碰撞
  checkCover(scene.value);}, 300);
  //13.队列占满，失败
  if(queue.value.length == 7){
    tipText.value = "失败了";
    finished.value = true;
  }
  //动画结束
  flag.value = false;
};

//6.队列排序
watchEffect(()=>{
  const cache = {};
      //1.让icon作为键将对应的元数据统计起来
      for(const symbol of queue.value){
        if(cache[symbol.icon]){
            //已经存在的键 push
            cache[symbol.icon].push(symbol);
        }else{
            //第一次生成的键
            cache[symbol.icon] = [symbol];
        }
      }
      //console.log(cache);
      // 2.循环cache中所有的Object.values(cache)中的值[{symbol1...},{symbol2...}],生成新的队列
      const newqueue = [];
      //Object.values(cache)
      for(const symbols of Object.values(cache)){
        newqueue.push(...symbols)        
      }
      console.log(newqueue);
      //3.循环新的排序队列，计算 对应的x坐标,生成数组sortedQueue
        const sQueue = {}
        let x = 50;
        for(const symbol of newqueue){
            sQueue[symbol.id] = x;
            x += 100;
        }
        sortedQueue.value = sQueue
        checkCover(scene.value);
})


//7.弹出
const tanchu = ()=> {
  if (!queue.value.length) return;
  const updateQueue = queue.value.slice();
  const symbol = updateQueue.shift();
  if (!symbol) return;
  const find = scene.value.find((s) => s.id === symbol.id);
  if (find) {
    queue.value = updateQueue;
    find.status = 0;
    find.x = 100 * Math.floor(8 * Math.random());
    find.y = 700;
    checkCover(scene.value);
  }
}



//8.撤销
const chexiao = () =>{
  if (!queue.value.length) return;
  const updateQueue = queue.value.slice();
  const symbol = updateQueue.pop();
  if (!symbol) return;
  const find = scene.value.find((s) => s.id === symbol.id);
  if (find) {
    queue.value = updateQueue;
    find.status = 0;
    checkCover(scene);
  }
}
//9.下一关
const leveNext = () =>{
  if(level.value >= maxLevel) return;
  finished.value = false;
  level.value = level.value + 1;
  queue.value = [];
  scene.value = makeScene(level.value)
  checkCover(scene.value)
}

// 10. restart
const restart = ()=>{
  finished.value = false;
  level.value =  1;
  queue.value = [];
  scene.value = makeScene(level.value);
  checkCover(scene.value)
}
</script>




<style lang="scss" scoped>
button {
  border-radius: 8px;
  border: 0;
  padding: 2% 4%;
  font-size: 14px;
  font-weight: bold;
  background-color: #000;
  color: #fff;
  cursor: pointer;
}

.bg {
  position: absolute; /*不占位的*/
  background: url("~@/assets/bg.png") no-repeat;
  background-size: 100% 100%;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}
.container {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  padding: 30px;
}
.wraper {
  width: 100%;
}
.scene-container {
  position: relative;
  width: 100%;
  height: 400px;
  margin: 10% 0;
}
.scene-inner {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}
.symbol {
  position: absolute;
  left: 0;
  top: 0;
  width: 12.5%;
  height: 12.5%;
  transition: all 0.3s;
}
.symbol-inner {
  position: absolute;
  left: 0;
  top: 0;
  display: flex;
  border: 2px solid #444;
  padding: 5px;
  border-radius: 8px;
  background: #fff;
}
img {
  width: 100%;
  height: 100%;
}
.queue-container {
  width: 100%;
  border: 2px solid #444;
  border-radius: 8px;
  padding-bottom: 15%;
  margin-bottom: 20px;
}
.btn-container {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.modal{
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
  align-content: center;
  justify-content: center;
  background:rgb(0,0,0,.2);
  color: #fff;
}
</style>
